package com.github.livebase.database;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.github.livebase.log.Formatter;
import com.github.livebase.log.LFormatter;
import com.github.livebase.log.LogUtil;
import com.github.livebase.log.Logger;
import com.github.livebase.log.LoggerFactory;
import com.github.livebase.log.ToStringRef;
import com.github.livebase.util.base.ObjectsUtil;

import java.util.List;

/**
 * @ClassName Op
 * @description:
 * @author: biao532
 * @create: 2024-02-18 20:20
 * @Version 1.0
 **/
public class OperatorHelper {
    private static String TAG = OperatorHelper.class.getSimpleName();
    private Formatter formatter;
    private Logger logger;
    private SQLiteDatabase wdb;
    private SQLiteDatabase rdb;
    protected OperatorHelper(SQLiteOpenHelper helper) {
        wdb = helper.getWritableDatabase();
        rdb = helper.getReadableDatabase();
        this.formatter = LFormatter.getFormatter();
        this.logger = LoggerFactory.getLogger(OperatorHelper.class);
    }

    public boolean exist(String tableName, String where, String[] args) {
        String sql = formatter.format("select 1 from {} where {} limit 1", tableName, where);
        Cursor c = rdb.rawQuery(sql, args);
        int rst = c.getCount();
        c.close();
        if (logger.isDebug()) {
            ToStringRef ref = LogUtil.acquireRef(args);
            logger.debug(TAG, "sql is {} args is {} result is {}", sql, ref, rst);
            LogUtil.releaseRef(ref);
        }

        return rst != 0;
    }
    public<T> List<T> selectList(String tableName, String[] cols, String condition, String[] bindArgs, ObjectsUtil.Converter<Cursor, T> converter) {
        StringBuilder builder = new StringBuilder();
        for (String key : cols) {
            builder.append(',');
            builder.append('`');
            builder.append(key);
            builder.append('`');
        }

        String sql = formatter.format("select {} from {} {}",
                builder.substring(1), tableName, condition);

        Cursor cursor = rdb.rawQuery(sql, bindArgs);
        List<T> t = OperatorUtil.cursorForeach(cursor, true, converter);
        cursor.close();

        if (logger.isDebug()) {
            ToStringRef ref = LogUtil.acquireRef(bindArgs);
            logger.debug(TAG, "sql is {}, args is {} result is {}", sql, ref, t);
            LogUtil.releaseRef(ref);
        }

        return t;
    }

    public<T> T select(String tableName, String[] cols, String condition, String[] bindArgs, ObjectsUtil.Converter<Cursor, T> converter) {
        StringBuilder builder = new StringBuilder();
        for (String key : cols) {
            builder.append(',');
            builder.append('`');
            builder.append(key);
            builder.append('`');
        }

        String sql = formatter.format("select {} from {} {} limit 1",
                builder.substring(1), tableName, condition);

        Cursor cursor = rdb.rawQuery(sql, bindArgs);
        T t = OperatorUtil.first(cursor, true, converter);
        cursor.close();
        if (logger.isDebug()) {
            ToStringRef ref = LogUtil.acquireRef(bindArgs);
            logger.debug(TAG, "sql is {} args is {} result is {}", sql, ref, t);
            LogUtil.releaseRef(ref);
        }
        return t;
    }
    public void upsert(String tableName, ContentValues contentValues) {
        StringBuilder builder = new StringBuilder();
        StringBuilder args = new StringBuilder();
        Object[] bindArgs = new Object[contentValues.size()];
        int i = 0;
        for (String key : contentValues.keySet()) {
            builder.append(',');
            builder.append('`');
            builder.append(key);
            builder.append('`');
            args.append(", ?");
            bindArgs[i++] = contentValues.get(key);
        }

        String sql = formatter.format("INSERT OR REPLACE INTO {}({}) VALUES ({})",
                tableName, builder.substring(1), args.substring(1));
        wdb.execSQL(sql, bindArgs);
        if (logger.isDebug()) {
            ToStringRef ref = LogUtil.acquireRef(bindArgs);
            logger.debug(TAG, "sql is {} args is {} result is {}", sql, ref, ObjectsUtil.Empty.STRING);
            LogUtil.releaseRef(ref);
        }
    }

    public int delete(String tableName, String where, String[] args) {
        int rst = rdb.delete(tableName, where, args);
        if (logger.isDebug()) {
            ToStringRef ref = LogUtil.acquireRef(args);
            logger.debug(TAG, "sql is delete from {} where {},  args is {} result is {}",tableName, where, ref, rst);
            LogUtil.releaseRef(ref);
        }
        return rst;
    }
}
